home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
psi110g.zip
/
FORWARD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-04
|
43KB
|
1,288 lines
/* Some of the code in this file was originally based on the following file:
* gateway.c : Paul Healy, EI9GL, 900818
*
* Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
* "X-BBS-To", added timer support, etc. Anders Klemets, SM0RGV, 901009.
*/
/* Mods by G1EMM and WG7J */
/* Mod to R: line to MSYS-style with bid by N2LSS: define MSYS_RLINE */
#include <ctype.h>
#include <time.h>
#include "global.h"
#ifdef MBFWD
#include "bm.h"
#include "mailbox.h"
#include "smtp.h"
#include "cmdparse.h"
#include "proc.h"
#include "socket.h"
#include "timer.h"
#include "usock.h"
#include "netuser.h"
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "files.h"
#include "index.h"
extern int MbForwarded;
extern char MboxId[];
#define ISPROMPT(s) (strlen(s) > 1 && s[strlen(s)-2] == '>')
static struct timer fwdtimer;
static struct proc *FwdProc;
static char *findident __ARGS((char *str, int n, char *result));
static void sendmsg __ARGS((struct fwd *f,int msgn));
static char *mbxtime __ARGS((time_t date));
static int fwdinit __ARGS((struct mbx *m));
static char *fwdanybbs __ARGS((struct mbx *m,int *poll));
static int timeok __ARGS((char *line));
static void fwdtick __ARGS((void *v));
static void fwdproc __ARGS((void));
static int isconnbbs __ARGS((struct mbx *m));
static void startfwd __ARGS((int a,void *v1,void *v2));
static int openconn __ARGS((int argc,char *argv[],void *p));
static int sendmsgtobbs __ARGS((struct fwd *f,int msgn,char *dest));
static int makecl __ARGS((struct fwd *f,int msgn,char *dest,char *line,char **subj,int *bul));
static char *grabtext __ARGS((char *from,char *to,int marker));
/***************************************************************************
findident copies the 'n'th alphanumeric sequence from 'str' to result.
It returns a ptr to result. It returns "\0" for missing identifier etc.
Uses isalnum macro to decide on alphanumeric/non-alnum status.
*/
static char *
findident(str, n, result)
char *str, *result;
int n;
{
int count; /* current identifier */
count = 0;
*result = '\0';
while ( (count<n) && (*str!='\0') ) { /* Process alnum or non alnum seq */
while ( (*str!='\0') && (!isalnum(*str)) ) /* Get rid of ';:.@%"# etc */
str++;
if ( (*str!='\0') && isalnum(*str) ) { /* this is an alnum seq */
count++;
while ( (*str!='\0') && (isalnum(*str) || (*str=='_')) )
if (count==n)
*result++ = *str++;
else str++;
if (count==n)
*result = '\0';
}
}
return result;
}
/**************************************************************************/
/* sendmsg() modified to send the R: line always.
* also added some additional strings like qth and zipcode etc. to R: line.
* Original SMTP headers get forwarded optionally.
* 920114 - WG7J
*/
extern char *Mbhaddress;
extern char *Mbfwdinfo;
extern char *Mbqth;
extern char *Mbzip;
extern int Mbsmtptoo;
extern int UtcOffset;
extern int Mbheader;
extern char shortversion[];
static void
sendmsg(f,msgn)
struct fwd *f;
int msgn;
{
struct mbx *m = f->m;
int i,rheader = 0;
long start;
char buf[LINELEN], tb[LINELEN], *cp;
/* If the data part of the message starts with "R:" the RFC-822
* headers will not be forwarded. Instead we will add an R:
* line of our own.
*/
/* ALWAYS forward with "R:" line - WG7J */
/* Now conditional upon Mbheader - 921201, WG7J */
if(Mbheader) {
/* First send recv. date/time and bbs address */
usprintf(m->user,"R:%s",mbxtime(f->ind.mydate));
#if defined(MSYS_RLINE)
/* Include the message number */
usprintf(m->user," %lu", f->ind.msgid);
#endif
/* If exists, send H-address */
if(Mbhaddress != NULLCHAR)
#if defined(MSYS_RLINE)
usprintf(m->user,"@%s",Mbhaddress);
#else
usprintf(m->user," @:%s",Mbhaddress);
#endif
/* location, if any */
if(Mbqth != NULLCHAR)
usprintf(m->user," [%s]",Mbqth);
/*if there is info, put it next */
if(Mbfwdinfo != NULLCHAR)
usprintf(m->user," %s",Mbfwdinfo);
#if !defined(MSYS_RLINE)
/* number of the message */
usprintf(m->user," #:%lu",f->ind.msgid);
#endif
/* The BID, is any */
if(f->bid[0] != '\0')
usprintf(m->user," $:%s",&f->bid[1]);
/* zip code of the bbs */
if(Mbzip != NULLCHAR)
usprintf(m->user," Z:%s",Mbzip);
usputc(m->user,'\n');
}
/* Open the mailbox file */
sprintf(buf,"%s/%s.txt",Mailspool,m->area);
if((m->mfile = fopen(buf,"r")) == NULL) {
usputs(m->user,"Can not find message body!\n");
#ifdef MAILERROR
mail_error("MBX FWD %s: Can not find mailfile for msg %d in %s", \
m->name,msgn,buf);
#endif
return;
}
/* point to start of this message in file */
start = m->mbox[msgn].start;
fseek(m->mfile,start,SEEK_SET);
/* If we also send the smtp headers, now see if the message
* has any R: headers. If so, send them first.
*/
if(Mbsmtptoo) {
while(fgets(buf,sizeof(buf),m->mfile) != NULL) {
if(*buf == '\n')
break; /* End of smtp headers */
}
if(ferror(m->mfile))
return;
/* Found start of msg text, check for R: lines */
while(fgets(buf,sizeof(buf),m->mfile) != NULL &&
!strncmp(buf,"R:",2)) {
rheader = 1;
usputs(m->user,buf);
}
/* again point to start of this message in file */
fseek(m->mfile,start,SEEK_SET);
}
/* Go past the SMTP headers to the data of the message.
* Check if we need to forward the SMTP headers!
* 920114 - WG7J
*/
if(Mbsmtptoo && (rheader || Mbheader))
usputc(m->user,'\n');
while(fgets(buf,sizeof(buf),m->mfile) != NULL &&
*buf != '\n') {
if(Mbsmtptoo) {
/* YES, forward SMTP headers TOO !*/
switch(htype(buf)) {
case XFORWARD: /* Do not forward the "X-Forwarded-To:" lines */
case STATUS: /* Don't forward the "Status:" line either */
case BBSTYPE:
case SUBJECT:
case TO:
case DATE:
break;
case FROM:
/* Don't forward the "From: " line either.
* make it ">From: "
*/
usputc(m->user,'>');
/*note fall-through*/
default:
if(!strncmp(buf,"From ",5))
usputc(m->user,'>');
usputs(m->user,buf);
}
}
}
/* Now we are at the start of message text.
* the rest of the message is treated below.
* Remember that R: lines have already been sent,
* if we sent smtp headers !
*/
i = 1;
while(fgets(buf,sizeof(buf),m->mfile) != NULL &&
strncmp(buf,"From ",5)) {
if(i) {
if(!strncmp(buf,"R:",2)) {
if(Mbsmtptoo) continue;
} else {
i = 0;
if(*buf != '\n')
/* Ensure body is separated from R: line */
usputc(m->user,'\n');
}
}
usputs(m->user,buf);
}
fclose(m->mfile);
m->mfile = NULL;
return;
}
/* Parse a line for date and time in Arpanet format
* (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
* (yymmdd/hhmmz)
*/
static char *
mbxtime(time_t date) {
time_t cdate; /* Date corrected for timezone offset */
extern char *Months[];
static char buf[13];
char *cp;
int month;
cdate = date;
/* adjust for GMT/UTC time - WG7J */
if(UtcOffset != 0)
cdate -= UtcOffset*3600L;
cp = ctime(&cdate);
/* Check month */
for(month=0; month < 12; ++month)
if(strnicmp(Months[month],cp+4,3) == 0)
break;
if(month == 12)
return NULL;
month++;
sprintf(buf,"%2.2s%02d%2.2s/%2.2s%2.2sz",cp+22,month,cp+8,cp+11,cp+14);
return buf;
}
static char *
grabtext(from, to, marker)
char *from, *to;
int marker;
{
while (*from!=marker)
*to++ = *from++;
*to = '\0';
return from+1;
}
/* Makes a command line and returns -1 if the message cannot be sent */
static int
makecl(f, msgn, dest, line, subj, bul)
struct fwd *f;
int msgn; /* Message number */
char *dest; /* Destination address to use instead of To: line */
char *line, **subj; /* Buffers to keep command line and subject */
int *bul; /* True if message is in public message area */
{
struct mbx *m = f->m;
struct let *cmsg = &m->mbox[msgn];
struct mailindex *ind = &f->ind;
struct fwdbbs *bbs;
int bulletin = *bul;
int foundbid = 0;
char *cp;
char *to,*atbbs;
char bid[60];
if((cmsg->status & BM_HOLD) || (!bulletin && (cmsg->status & BM_READ)))
return -1; /* the message was on hold or already read */
/* The following code tries to parse the "To: " line where the
* address looks like "to", "to@atbbs", or "to%atbbs@host"
*/
to = ind->to;
if((atbbs = strchr(to,'%')) != NULL) {
*atbbs++ = '\0'; /* "to" ends at the '%' character */
/* Now get rid of the following '@host' field */
if((cp = strchr(atbbs,'@')) != NULL)
*cp = '\0';
}
if((cp = strchr(to,'@')) != NULL) {
*cp = '\0'; /* "to" or "atbbs" ends at the '@' character */
if(!atbbs)
atbbs = cp + 1;
}
/*
if(!atbbs )
atbbs = to;
*/
/* "to" or "atbbs" should not be more than 6 characters (ALEN).
* If "to" is too long, it might simply be because the area name
* is longer than 6 characters, but it might also be because
* the address on the To: line is in an obscure format that we
* failed to parse (eg '!' character notation.)
*/
if(strlen(to) > ALEN) {
/* Play safe and set "to" and "atbbs" to the area name */
to = m->area;
atbbs = m->area;
}
to=strdup(to);
atbbs=strdup(atbbs);
if(strlen(to) > ALEN)
to[ALEN] = '\0'; /* Maximum length is 6 */
/* Only if the BBS supports "hierarchical routing designators"
* is the atbbs field allowd to be longer than 6 characters and
* have dots in it.
*/
if((m->sid & MBX_HIER_SID) == 0) {
if(atbbs && strlen(atbbs) > ALEN)
atbbs[ALEN] = '\0'; /* 6 character limit */
if(atbbs && (cp = strchr(atbbs,'.')) != NULLCHAR)
*cp = '\0'; /* cut "atbbs" at first dot */
}
/* The following code distinguishes between three different types
* of Message-IDs: abcde@callsign.bbs, abcde@otherhost.domain,
* and abcde@ourhost.domain.
* The first type is converted to $abcde and the second to
* $abcde_host.domain. The last to $abcde_first-part-of-H-address.
* This preserves compability with BBSes.
*/
f->bid[0] = '\0';
strncpy(&bid[1],ind->messageid,sizeof(bid) - 1);
bid[sizeof(bid)-1] = '\0';
/* Is there a @hostname part ? */
if((cp = strchr(&bid[1],'@')) != NULL) {
bid[0] = '$';
if(stricmp(cp+strlen(cp) - 4, ".bbs") == 0) {
/*retain the bid given by user*/
*cp = '\0';
foundbid = 1; /* Indicate we found a 'real' bid - WG7J */
} else {
*cp++ = '_';
if(Mbhaddress && !strcmp(cp,Hostname)) {
/* This is one of our messages!
* Take the _host part from the H-address,
* to form our bid - WG7J 930205
*/
strcpy(cp,Mbhaddress);
}
/* This is now either $msg#@my_h-address, or $msg#_host.domain
* make this BID style '$msg#_host'
* ie. cut off after first period - WG7J
*/
if((cp = strchr(cp,'.')) != NULL)
*cp = '\0';
}
bid[13] = '\0'; /* BIDs should be no longer than 13 bytes */
strcpy(f->bid,bid);
}
if(ind->from) {
if((cp=strchr(ind->from,'@')) != NULL)
*cp = '\0';
if((cp=strchr(ind->from,'%')) != NULL)
*cp = '\0';
if(strstr(ind->from,m->name) != NULL) {
/* This message came from the connected BBS so Abort */
free(to);
free(atbbs);
return -1;
}
if(strlen(ind->from) > ALEN)
ind->from[ALEN] = '\0'; /* 6 character limit */
}
if((*to == '\0' && ((dest != NULL && *dest == '\0') ||
dest == NULL)) || *ind->from == '\0') {
free(to);
free(atbbs);
return -1;
}
if(line != NULL) {
if(dest != NULL && *dest != '\0'){
/* strip off hierarchical routing designators from the predefined
* destination address if they are not supported
*/
if((m->sid & MBX_HIER_SID) == 0 && (cp = strchr(dest,'.')) !=
NULLCHAR)
*cp = '\0';
sprintf(line, "S%c %s < %s ", ind->type, dest, ind->from);
} else {
if(atbbs)
sprintf(line, "S%c %s @ %s < %s ", ind->type, to, atbbs, ind->from);
else
sprintf(line, "S%c %s < %s ", ind->type, to, ind->from);
}
/* Add the bid to bulletins,
* AND ALSO to anything that came in with a bid !
* Takes care off duplicate 'SP SYSOP@xxx $BID' problems.
* ALSO add it to ALL messages if the remote system supports MID's - WG7J
*/
if((m->sid & MBX_MID) || ((bulletin || foundbid) & (m->sid & MBX_SID)))
strcat(line,f->bid);
strcat(line,"\n");
}
if(subj)
*subj = strdup(ind->subject);
free(to);
free(atbbs);
return 0;
}
static int /* 0 = ok, -1 = problem so disc */
sendmsgtobbs(f, msgn, dest)
struct fwd *f;
int msgn;
char *dest; /* Optional destination address to override To: line */
{
int result = -1;
struct mbx *m = f->m;
struct fwdbbs *bbs;
int bulletin = (m->areatype == AREA);
char *subj = NULL;
char line[64];
/* Check x-forwarded-to fields */
for(bbs=f->ind.bbslist;bbs;bbs=bbs->next)
if(!stricmp(bbs->call,m->name))
return 0;
if(makecl(f, msgn, dest, line, &subj, &bulletin) == -1)
return 0; /* do not forward this particular message */
tputs(line); /* Send mail offer to bbs */
/* rip(line); */
usflush(m->user);
if(recvline(m->user, m->line, MBXLINE) != -1 ) {
if(m->line[0] == 'O' || m->line[0] == 'o' || (m->sid & MBX_SID) == 0) {
/* Got 'OK' or any line if the bbs is unsofisticated */
tprintf("%s\n", subj);
sendmsg(f,msgn); /* send the message */
#ifdef FWDCTLZ
/* Some bbs code doesn't like /EX too well... */
tputs("\032\n");
#else
tputs("/EX\n"); /* was 0x1a */
#endif
usflush(m->user);
/* get F> for a good deliver */
while (recvline (m->user, m->line, MBXLINE) != -1 ) {
if(ISPROMPT(m->line)) {
rip(line); /* N5KNX: now drop NL for nicer log entry */
log(m->user,"MBOX bbs mail sent: %s ", line);
if(m->areatype == AREA)
m->mbox[msgn].status |= BM_FORWARDED;
else
m->mbox[msgn].status |= BM_DELETE;
m->change = 1;
result = 0;
MbForwarded++;
break;
}
}
} else { /* OK response not received from bbs */
if (m->line[0] == 'N' || m->line[0] == 'n') { /* 'NO' respone */
rip(m->line); /* N5KNX: nicer log entry */
log(m->user,"MBOX bbs mail refused: %s\t%s",line,m->line);
/* Mark refused message as forwarded if it is a bulletin.
* The message was probably a duplicate. Non-bulletin
* messages are sent without BID, so they cannot be dected
* as duplicates. The reason why it was refused is probably
* because the address was invalid. Retry later.
*
* After lots of complaining, this behaviour is changed:
* ALL messages that get the NO reply are marked
* as forwarded ! - WG7J 930124
*/
if(m->areatype == AREA)
m->mbox[msgn].status |= BM_FORWARDED;
else
m->mbox[msgn].status |= BM_DELETE;
m->change = 1;
/* Count this as forwarded ! - WG7J */
MbForwarded++;
}
/* should get a F> here */
while (recvline (m->user, m->line, MBXLINE) != -1 ) {
if (ISPROMPT(m->line)) {
result = 0;
break;
}
}
}
} /* OK or NO here */
free(subj);
return result;
}
/* This is the main entry point for reverse forwarding. It is also used
* for normal, "forward", forwarding.
*/
int
dorevfwd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char *cp, *dp;
int i, idx, err = 0;
struct fwd f;
struct indexhdr hdr;
struct fwdbbs *bbs;
char fn[64];
char oldarea[64];
long before,after;
f.m = (struct mbx *)p;
memset(&f.ind,0,sizeof(struct mailindex));
log(f.m->user,"MBOX forwarding mail to: %s ", f.m->name);
/* indicate we are doing reverse forwarding, if we are not already
* doing normal forwarding.
*/
if(f.m->state != MBX_FORWARD)
f.m->state = MBX_REVFWD;
if(fwdinit(f.m) != -1) {
strcpy(oldarea,f.m->area);
while(!err && fgets(f.m->line,MBXLINE,f.m->tfile) != NULLCHAR) {
pwait(NULL);
if(*f.m->line == '-') /* end of record reached */
break;
cp = f.m->line;
rip(cp); /* adds extra null at end */
/* skip spaces */
while(*cp && (*cp == ' ' || *cp == '\t'))
cp++;
if(*cp == '\0' || *cp == '.' || *cp == '#' || *cp == '+' || *cp == '&' || *cp == '@')
continue; /* ignore empty or connect-script lines */
/* find end of area name, and beginning of optional destination string */
for (dp=cp; *dp && *dp != ' ' && *dp != '\t' && *dp != '\n'; dp++) ;
if (*dp) *dp++ = '\0';
changearea(f.m,cp);
/* Now create the index filename */
sprintf(fn,"%s/%s.ind",Mailspool,cp);
/* strip leading blanks from dest */
cp=dp;
while(*cp && (*cp == ' ' || *cp == '\t'))
cp++;
/* find end of optional destination */
for (dp=cp; *dp && *dp != ' ' && *dp != '\t' && *dp != '\n'; dp++) ;
if (*dp) *dp = '\0';
cp = strdup(cp);
/* open the index file */
if((idx=open(fn,READBINARY)) != -1) {
/* check if there are any messages in this area
* that need to be forwarded.
*/
if(read_header(idx,&hdr) != -1) {
for(i=1; i<=f.m->nmsgs; i++) {
pwait(NULL);
if(read_index(idx,&f.ind) == -1) {
err = 1;
break;
}
if(sendmsgtobbs(&f, i, cp) == -1) {
err = 1; /* abort */
break;
}
/* Done with this index, clear it */
default_index(f.m->area,&f.ind);
scanmail(f.m);
}
}
close(idx);
idx = 0;
}
if(f.m->mfile) {
fclose(f.m->mfile);
f.m->mfile = NULL;
}
free(cp);
}
fclose(f.m->tfile);
f.m->tfile = NULLFILE;
if(*oldarea != '\0')
changearea(f.m,oldarea);
}
default_index("",&f.ind);
if(f.m->state == MBX_FORWARD)
return 0;
tputs("*** Done\n");
#ifdef notdef
/* Can't do this with polling anymore */
if((f.m->sid & MBX_RLI_SID)) /* disconnect if it is a W0RLI bbs */
return domboxbye(0,NULL,f.m);
#endif
return 0;
}
/* Read the forward file for a record for the connected BBS. If found,
* return 1 if this is the right time to forward, m->tfile is left pointing
* at the first message area to be forwarded.
*/
static int
fwdinit(m)
struct mbx *m;
{
char host[80];
int start = 1;
if((m->tfile = fopen(Forwardfile,READ_TEXT)) == NULLFILE)
return -1;
while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
if(*m->line == '\n')
continue;
/* lines starting with '-' separate the forwarding records */
if(*m->line == '-') {
start = 1;
continue;
}
if(start) {
start = 0;
/* get the name of this forwarding record */
findident(m->line,1,host);
if(stricmp(m->name,host) == 0) {
if(!timeok(m->line))
break;
/* eat the connect command line */
fgets(m->line,MBXLINE,m->tfile);
return 0;
}
}
}
fclose(m->tfile);
m->tfile = NULLFILE;
return -1;
}
/* Read the forward file for a record for the connected BBS. If found,
* determine if this is the right time to forward, and return the command
* line to establish a forwarding connection. m->tfile is left pointing
* at the first message area to be forwarded.
*/
static char *
fwdanybbs(m,poll)
struct mbx *m;
int *poll;
{
char host[80];
int start = 1,i;
if(m->tfile == NULLFILE && (m->tfile = fopen(Forwardfile,READ_TEXT))
== NULLFILE)
return NULLCHAR;
*poll = 0; /* Default to no polling */
while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
if(*m->line == '\n')
continue;
/* lines starting with '-' separate the forwarding records */
if(*m->line == '-') {
start = 1;
continue;
}
if(start) {
start = 0;
/* get the name of this forwarding record */
findident(m->line,1,host);
strcpy(m->name,host);
if(!timeok(m->line))
continue; /* too late or too early */
/* Check for polling - WG7J */
i=2;
findident(m->line,2,host);
while(*host) {
if(*host == 'P' || *host == 'p') {
*poll = 1;
break;
}
i++;
findident(m->line,i,host);
}
/* get the connect command line */
fgets(m->line,MBXLINE,m->tfile);
return strdup(m->line);
}
}
fclose(m->tfile);
m->tfile = NULLFILE;
return NULLCHAR;
}
/* get any groups of four digits that specify the begin and ending hours of
* forwarding. Returns 1 if forwarding may take place.
*/
static int
timeok(line)
char *line;
{
char hours[80], *now;
long t;
int t1, t2, pos = 2;
findident(line,pos++,hours);
if(*hours == '\0' || *hours == 'P' || *hours == 'p')
return 1; /* no digits default to 0023, ie. anytime */
time(&t);
now = ctime(&t) + 11;
*(now + 2) = '\0';
while(*hours != '\0') {
t1 = (*hours - '0') * 10 + (*(hours+1) - '0');
t2 = (*(hours+2) - '0') * 10 + (*(hours+3) - '0');
if(atoi(now) >= t1 && atoi(now) <= t2)
return 1; /* right in time */
findident(line,pos++,hours); /* get next group if any */
if(*hours == 'P' || *hours == 'p')
return 0;
}
return 0; /* too early or too late */
}
int
dombtimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Forwarding timer: %lu/%lu server %s.\n",
read_timer(&fwdtimer)/1000L,
dur_timer(&fwdtimer)/1000L,
FwdProc != NULLPROC ? "started":"stopped");
return 0;
}
fwdtimer.func = (void (*)__ARGS((void *)))fwdtick;/* what to call on timeout */
fwdtimer.arg = NULL; /* dummy value */
set_timer(&fwdtimer,atol(argv[1])*1000L); /* set timer duration */
pwait(NULL);
if (FwdProc != NULLPROC) /* if someone is listening */
start_timer(&fwdtimer); /* fire it up */
else
if(dur_timer(&fwdtimer) != 0)
tputs("Warning: forward server not started.\n");
return 0;
}
int
dombkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if (FwdProc == NULLPROC) {
tputs("Forward server not started\n");
return 1;
}
psignal(&fwdtimer,0);
return 0;
}
/* called when the forward timer expires or explicitly by dombkick() */
/* MDMII: fwdproc is the old fwdtick. But, since it can call pause, which is
* very very bad for timer functions :-( this has been converted to a server.
*/
static void
fwdtick(v)
void *v;
{
psignal(&fwdtimer,0); /* awake the forwarder */
start_timer(&fwdtimer); /* and restart the timer */
}
/* the main process for the mailbox forwarder */
int
fwdstart(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if (FwdProc != NULLPROC)
return 0; /* already started */
FwdProc = Curproc; /* set our flag */
psignal(Curproc,0); /* don't wait on us */
start_timer(&fwdtimer); /* start timer (ignored if 0) */
for (;!pwait(&fwdtimer);) /* wait for someone to tell us to try */
if (availmem() > Memthresh)
fwdproc();
else if(Mtrace)
tputs("fwd: forwarding skipped due to low memory\n");
FwdProc = NULLPROC; /* we are exiting */
return 0; /* alerted from somewhere */
}
/* (attempt to) kill the forwarder process */
int
fwd0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i, max; /* max attempts */
stop_timer(&fwdtimer); /* no more timer awakes */
max = 1; /* Maximum attempts */
if (argc > 2)
setint(&max,NULLCHAR,argc,argv);
for(i=0;i<max && FwdProc != NULLPROC;i++) {
alert(FwdProc,1); /* signal regardless of location */
pwait(NULL); /* let it see the alert */
}
stop_timer(&fwdtimer); /* in case timer tick restarted it */
return 0;
}
/* MDMII: This is the old fwdtick function */
static void
fwdproc(void)
{
char *cc, *cp, *fp;
struct mbx *m;
struct fwdbbs *bbs;
struct indexhdr hdr;
struct mailindex ind;
int i, idx, bulletin, poll,skip = 0;
char fn[FILE_PATH_SIZE];
if(Mtrace)
tputs("mbox: fwd started\n");
if((m = newmbx()) == NULLMBX){
if(Mtrace)
tputs("fwd: no new mbox\n");
return;
}
m->user = Curproc->output;
m->state = MBX_TRYING;
memset(&ind,0,sizeof(struct mailindex));
while((cc = fwdanybbs(m,&poll)) != NULLCHAR) {
if(isconnbbs(m)) { /* already connected to this BBS, skip it */
skip = 1;
if(Mtrace)
tprintf("fwd: %s already connected\n",m->name);
}
/* If we poll, there is no need to check message area, since this
* is also done later. It will speed things up here - WG7J
*/
if(!skip && poll) {
if(Mtrace)
tprintf("fwd: polling %s\n",m->name);
newproc("Mbox forwarding", 2048,startfwd, 0, (void *)cc,
(void *)strdup(m->name),0);
cc = NULLCHAR;
skip = 1;
}
if(!skip && Mtrace)
tprintf("fwd: %s - checking for messages\n",m->name);
while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
pwait(NULL);
if(*m->line == '-') { /* end of record reached */
skip = 0;
break;
}
if((cp = strchr(m->line,' ')) != NULLCHAR)
*cp = '\0';
if((cp = strchr(m->line,'\t')) != NULLCHAR)
*cp = '\0';
if(skip || *m->line == '\0' || *m->line == '#' || *m->line == '.' || \
*m->line == '+' || *m->line == '@' || *m->line == '&')
continue;
rip(m->line);
bulletin = isarea(m->line); /* public area */
sprintf(fn,"%s/%s.ind",Mailspool,m->line);
if((idx=open(fn,READBINARY)) != -1) {
/* check if there are any messages in this area
* that need to be forwarded.
*/
if(read_header(idx,&hdr) == -1)
hdr.msgs = 0;
for(i=1; i<=hdr.msgs; i++) {
pwait(NULL);
/* Done with this index, clear it */
default_index("",&ind);
if(read_index(idx,&ind) == -1)
break; /* Should not happen ! */
/* Apply same tests as in makecl() */
if(ind.status & BM_HOLD) continue;
if(bulletin) {
for(bbs = ind.bbslist;bbs;bbs=bbs->next)
if(!stricmp(bbs->call,m->name))
break;
if(bbs)
continue;
} else if(ind.status & BM_READ)
continue;
if(ind.from) { /* Don't fwd back to originator */
fp=strdup(ind.from);
if((cp=strchr(fp,'@')) != NULL)
*cp = '\0';
if((cp=strchr(fp,'%')) != NULL)
*cp = '\0';
if(strstr(fp,m->name) != NULL) {
free(fp);
continue;
}
free(fp);
}
if(Mtrace)
tprintf("fwd: starting %s (%s,#%d)\n",m->name, m->line, i);
newproc("Mbox forwarding", 2048,
startfwd, 0, (void *)cc,
(void *)strdup(m->name),0);
skip = 1;
cc = NULLCHAR;
break;
}
/* Done with this index, clear it */
default_index("",&ind);
close(idx);
}
}
free(cc);
}
default_index("",&ind);
usesock(Curproc->output); /* compensate for close_s() in exitbbs */
exitbbs(m);
}
/* returns 1 if m->name matches the name of another connected mailbox. */
static int
isconnbbs(m)
struct mbx *m;
{
struct mbx *mp;
for(mp=Mbox;mp;mp=mp->next)
if((stricmp(mp->name,m->name) == 0) && (mp->state != MBX_TRYING) )
return 1;
return 0;
}
/* possible commands on the command line in the forwarding file */
static struct cmds cfwdcmds[] = {
"tcp", openconn, 0, 0, NULLCHAR,
"telnet", openconn, 0, 0, NULLCHAR,
#ifdef AX25
"ax25", openconn, 0, 0, NULLCHAR,
"connect", openconn, 0, 0, NULLCHAR,
#endif
#ifdef NETROM
"netrom", openconn, 0, 0, NULLCHAR,
#endif
NULLCHAR
};
int FwdUsers;
void exitfwd(struct mbx *m) {
FwdUsers--;
if(m->state != MBX_TRYING) log(m->user,"MBOX fwd exit: %s",m->name); /* N5KNX: log exits */
exitbbs(m);
}
/* this function is called whenever the forwarding timer expires */
static void
startfwd(a,v1,v2)
int a;
void *v1, *v2;
{
struct mbx *m;
char *cc;
int32 timeout;
int rval;
char *cp;
char Continue[MBXLINE];
cc = (char *) v1;
if((m = newmbx()) == NULLMBX) {
free(cc);
free((char *)v2);
return;
}
FwdUsers++;
strcpy(m->name,(char *)v2);
free((char *)v2);
m->state = MBX_TRYING;
/* open the connection, m->user will be the new socket */
if(cmdparse(cfwdcmds,cc,(void *)m) == -1) {
free(cc);
usesock(Curproc->output); /* compensate for close_s() in exitbbs */
exitfwd(m);
return;
}
free(cc);
m->state = MBX_FORWARD;
sockowner(m->user,Curproc);
close_s(Curproc->output);
close_s(Curproc->input);
/* m->user will be closed automatically when this process exits */
Curproc->output = Curproc->input = m->user;
/* We'll do our own flushing right before we read input */
setflush(m->user,-1);
if(fwdinit(m) == -1) {
/* it is probably not the right time to forward anymore */
exitfwd(m);
return;
}
/* read the connect script. Lines starting with a dot will be sent
* to the remote BBS.
*/
Continue[0] = '\0';
while((cp=fgets(m->line,MBXLINE,m->tfile)) != NULLCHAR) {
/* Expanded to do timeouts, and return string recognition - WG7J */
switch(*m->line) {
case '.': /* send this line */
tputs(m->line + 1);
if(Mtrace)
printf("fwd: %s > %s\n",m->name,m->line+1);
Continue[0] = '\0'; /* reset reply string */
break;
case '#': /* comment line, ignore */
break;
case '+': /* string upon wich we continue ! */
strcpy(Continue,m->line+1);
rip(Continue); /* get rid of \n */
break;
case '&': /* Wait a certain number of seconds */
timeout = atol(m->line+1);
pause(timeout * 1000L);
break;
case '@': /* string that sets timeout */
timeout = atol(m->line+1);
if(timeout) /* if a valid conversion */
timeout *= 1000; /* in ms ! */
else
timeout = 90*1000L; /* default to 1.5 minutes */
if(Mtrace)
printf("fwd: %s, wait %ld < %s\n",m->name,timeout/1000,Continue);
/* Now do the actual response interpretations */
alarm(timeout);
rval = recvline(m->user,m->line,MBXLINE);
alarm(0L);
/* Did we timeout, or connection disappear ? */
if(Mtrace) {
printf("fwd: %s, rx %d",m->name,rval);
if(rval >= 0)
printf(", %s",m->line);
else
putchar('\n');
}
if((rval < 0) || (strstr(m->line,Continue) == NULLCHAR)) {
if(Mtrace)
printf("fwd: %s, aborted!\n",m->name);
exitfwd(m);
return;
}
Continue[0] = '\0'; /* reset reply string */
break;
default: /* must be the end of the script */
goto go_on;
}
usflush(m->user); /* send it, if any */
}
/* Now we've past all in-between stuff, go talk to the bbs ! */
go_on:
usflush(m->user);
fclose(m->tfile);
m->tfile = NULLFILE;
/* make sure there is something left ! */
if(cp == NULLCHAR) {
if(Mtrace)
puts("fwd: forward.bbs error!");
exitfwd(m);
return;
}
if(Mtrace)
printf("fwd: %s, script done\n",m->name);
/* read the initial output from the bbs, looking for the SID */
for(;;) {
if(recvline(m->user,m->line,MBXLINE) == -1) {
exitfwd(m);
return;
}
if(ISPROMPT(m->line))
break;
if(*m->line == '[') { /* parse the SID */
rip(m->line);
mbx_parse(m);
continue;
}
}
/* Now sync the two ends as telnet password messes them up */
if(socklen(m->user,0)) /* discard any remaining input */
recv_mbuf(m->user,NULL,0,NULLCHAR,0);
/* send our SID if the peer announced its SID */
if(m->sid & MBX_SID) {
tputs(MboxId);
usflush(m->user);
for(;;) {
if(recvline(m->user,m->line,MBXLINE) == -1) {
exitfwd(m);
return;
}
if(ISPROMPT(m->line))
break;
}
}
/* start the actual forwarding */
dorevfwd(0,NULL,(void *)m);
/* ask for reverse forwarding or just disconnect */
if(((m->sid & MBX_SID) && tputs("F>\n") == -1) ||
(m->sid & MBX_SID) == 0) {
exitfwd(m);
/* close_s(Curproc->output); exitfwd() calls exitbbs() which does this! */
return;
}
usflush(m->user);
/* parse the commands that are are received during reverse
* forwarding.
*/
while(recvline(m->user,m->line,MBXLINE) > 0) {
rip(m->line);
if(mbx_parse(m) == -2) /* got the "*** Done" command */
break;
tputs("F>\n");
usflush(m->user);
}
exitfwd(m);
/* close_s(Curproc->output); exitfwd() calls exitbbs() which does this! */
}
/* open a network connection based upon information in the cc line.
* m->user is set to the socket number.
*/
static int
openconn(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char sock[MAXSOCKSIZE], alias[AXBUF];
struct nrroute_tab *rp;
union sp sp;
int len;
char *remote;
m = (struct mbx *)p;
sp.p = sock;
if(argc < 2) {
if(Mtrace)
tputs("fwd: connect command error\n");
return -1;
}
remote = argv[1];
switch(*argv[0]) {
case 't':
sp.in->sin_family = AF_INET;
if((sp.in->sin_addr.s_addr = resolve(argv[1])) == 0) {
if(Mtrace)
tprintf("fwd: telnet - unknown host %s\n",argv[1]);
return -1;
}
/* get the optional port number */
if(argc > 2)
sp.in->sin_port = atoip(argv[2]);
else
sp.in->sin_port = IPPORT_TELNET;
if((m->user = socket(AF_INET,SOCK_STREAM,0)) == -1) {
if(Mtrace)
tputs("fwd: unable to open telnet socket\n");
return -1;
}
len = sizeof(*sp.in);
m->family = AF_INET; /*So the user list will be correct! - WG7J */
break;
#ifdef AX25
case 'a':
case 'c': /* allow 'c' for 'connect' as well */
if(argc < 3) {
if(Mtrace)
tprintf("fwd: connect syntax error - %s %s ?\n",argv[0],argv[1]);
return -1;
}
sp.ax->sax_family = AF_AX25;
strncpy(sp.ax->iface,argv[1],ILEN); /* the interface name */
setcall(sp.ax->ax25_addr,argv[2]); /* the remote callsign */
/* no digipeaters for now, use the "ax25 route add" command */
if((m->user = socket(AF_AX25,SOCK_STREAM,0)) == -1) {
if(Mtrace)
tputs("fwd: Unable to open ax25 socket\n");
return -1;
}
len = sizeof(*sp.ax);
m->family = AF_AX25; /*So the user list will be correct! - WG7J */
remote = argv[2];
break;
#endif /* AX25 */
#ifdef NETROM
case 'n':
/* See if the requested destination could be an alias, and
* use it if it is. Otherwise assume it is an AX.25
* address.
*/
putalias(alias,argv[1],0);
strupr(argv[1]);
if ((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB) {
if(Mtrace)
tprintf("fwd: Netrom route unavailable - %s\n",argv[1]);
return -1;
}
/* Setup the local side of the connection */
sp.nr->nr_family = AF_NETROM;
len = sizeof(*sp.nr);
if((m->user = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1) {
if(Mtrace)
tprintf("fwd: unable to open netrom socket - %s\n",argv[1]);
return -1;
}
memcpy(sp.nr->nr_addr.user,Nr4user,AXALEN);
memcpy(sp.nr->nr_addr.node,Nr_iface->hwaddr,AXALEN);
bind(m->user,sp.p,len);
/* Now the remote side */
memcpy(sp.nr->nr_addr.node,rp->call,AXALEN) ;
/* The user callsign of the remote station is never
* used by NET/ROM, but it is needed for the psocket() call.
*/
memcpy(sp.nr->nr_addr.user,rp->call,AXALEN) ;
m->family = AF_NETROM; /*So the user list will be correct! - WG7J */
break;
#endif /* NETROM */
default:
if(Mtrace)
tprintf("fwd: Invalid connect mode - %s\n",argv[0]);
return -1;
}
sockmode(m->user,SOCK_ASCII);
if(connect(m->user,sp.p,len) == -1) {
log(m->user,"MBOX fwd failed: %s - %s errno %d",
remote,sockerr(m->user),errno);
if(Mtrace)
tprintf("fwd: Connection failed to %s\n",remote);
close_s(m->user);
return -1;
}
return m->user;
}
#endif /*MBFWD*/